/*
 * copyright (c) 2013 Blaise-Florentin Collin
 *
 * This file is part of astroDCAM.
 *
 * AstroAviBrowser is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License v3
 * as published by the Free Software Foundation
 *
 * AstroAviBrowser is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * v3 along with AstroAviBrowser; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA
 */


///
/// \file dc1394camera.cpp
/// \brief Object wrapper for the dc1394 api (camera part) (code)
///

// dc1394 includes
#include <dc1394/log.h>

// C++ app includes
#include "config.hpp"
#include "dc1394camera.hpp"

// name spaces
using namespace std;

// All the IIDC available frame rates
const vector <dc1394rate> dc1394rates={
    {DC1394_FRAMERATE_1_875,"1.875 fps (533 ms)",533},
    {DC1394_FRAMERATE_3_75,"3.75 fps (266 ms)",266},
    {DC1394_FRAMERATE_7_5,"7.5 fps (133 ms)",133},
    {DC1394_FRAMERATE_15,"15 fps (66 ms)",66},
    {DC1394_FRAMERATE_30,"30 fps (33 ms)",33},
    {DC1394_FRAMERATE_60,"60 fps (16 ms)",16},
    {DC1394_FRAMERATE_120,"120 fps (8 ms)",8},
    {DC1394_FRAMERATE_240,"240 fps (4 ms)",4}
};

// All the IIDC available video modes
// Format 7 not supported yet
const vector<dc1394mode> dc1394modes={
   {DC1394_VIDEO_MODE_MIN,"160x120 YUV 4:4:4",160,120,YUV444},
   {DC1394_VIDEO_MODE_MIN+1,"320x240 YUV 4:2:2",320,240,YUV422},
   {DC1394_VIDEO_MODE_MIN+2,"640x480 YUV 4:1:1",640,480,YUV411},
   {DC1394_VIDEO_MODE_MIN+3,"640x480 YUV 4:2:2",640,480,YUV422},
   {DC1394_VIDEO_MODE_MIN+4,"640x480 RGB 24",640,480,RGB24},
   {DC1394_VIDEO_MODE_MIN+5,"640x480 Mono 8",640,480,MONO8},
   {DC1394_VIDEO_MODE_MIN+6,"640x480 Mono 16",640,480,MONO16},
   {DC1394_VIDEO_MODE_MIN+7,"800x600 YUV 4:2:2",800,600,YUV422},
   {DC1394_VIDEO_MODE_MIN+8,"800x600 RGB 24",800,600,RGB24},
   {DC1394_VIDEO_MODE_MIN+9,"800x600 Mono 8",800,600,MONO8},
   {DC1394_VIDEO_MODE_MIN+10,"1024x768 YUV 4:2:2",1024,768,YUV422},
   {DC1394_VIDEO_MODE_MIN+11,"1024x768 RGB 24",1024,768,RGB24},
   {DC1394_VIDEO_MODE_MIN+12,"1024x768 Mono 8",1024,768,MONO8},
   {DC1394_VIDEO_MODE_MIN+13,"800x600 Mono 16",800,600,MONO16},
   {DC1394_VIDEO_MODE_MIN+14,"1024x768 Mono 16",1024,768,MONO16},
   {DC1394_VIDEO_MODE_MIN+15,"1280x960 YUV 4:2:2",1280,960,YUV422},
   {DC1394_VIDEO_MODE_MIN+16,"1280x960 RGB 24",1280,960,RGB24},
   {DC1394_VIDEO_MODE_MIN+17,"1280x960 Mono 8",1280,960,MONO8},
   {DC1394_VIDEO_MODE_MIN+18,"1600x1200 YUV 4:2:2",1600,1200,YUV422},
   {DC1394_VIDEO_MODE_MIN+19,"1600x1200 RGB 24",1600,1200,RGB24},
   {DC1394_VIDEO_MODE_MIN+20,"1600x1200 Mono 8",1600,1200,MONO8},
   {DC1394_VIDEO_MODE_MIN+21,"1280x960 Mono 16",1280,960,MONO16},
   {DC1394_VIDEO_MODE_MIN+22,"1600x1200 Mono 16",1600,1200,MONO16}
   // Last modes to be added...
};

//
// Main constructor
//
dc1394camera::dc1394camera(dc1394_t* bus,uint64_t guid) {
   camera_handler=NULL;
   streamOn=false;

   // get the camera
   bus_handler=bus;
   camera_handler=dc1394_camera_new(bus_handler,guid);
}


//
// Main destructor
//
dc1394camera::~dc1394camera() {
   dc1394_camera_free(camera_handler);
}

//
// Get supported modes
//
vector<dc1394mode> dc1394camera::getSupportedModes() {
   dc1394video_modes_t modes;
   vector<dc1394mode> supportedModes;

   dc1394_video_get_supported_modes(camera_handler,&modes);
   for(int i=0;i<modes.num;i++) {
      if((modes.modes[i]-DC1394_VIDEO_MODE_MIN)<dc1394modes.size())
         supportedModes.push_back(dc1394modes[modes.modes[i]-DC1394_VIDEO_MODE_MIN]);
   }
   return(supportedModes);
}

//
// Get supported frame rates
//
vector<dc1394rate> dc1394camera::getSupportedRates() {
   dc1394framerates_t rates;
   vector<dc1394rate> supportedRates;

   dc1394_video_get_supported_framerates(camera_handler,current_mode,&rates);
   for(int i=0;i<rates.num;i++) {
      if((rates.framerates[i]-DC1394_FRAMERATE_MIN)<dc1394rates.size())
         supportedRates.push_back(dc1394rates[rates.framerates[i]-DC1394_FRAMERATE_MIN]);
   }

   return(supportedRates);
}

//
// Set the video mode
//
dc1394error dc1394camera::setMode(int m) {
   if(dc1394_video_set_mode(camera_handler,(dc1394video_mode_t)m)==DC1394_SUCCESS) {
      TRACE("[dc1394camera] : setMode " << dc1394modes[m-DC1394_VIDEO_MODE_MIN].name)
      current_mode=(dc1394video_mode_t)m;
      return(_NO_ERROR_);
   } else
      return(_NO_VIDEOMODE_);
}

//
// Set the frame rate
//
dc1394error dc1394camera::setRate(int m) {
   if(dc1394_video_set_framerate(camera_handler,(dc1394framerate_t)m)==DC1394_SUCCESS) {
      TRACE("[dc1394camera] : setRate " << dc1394rates[m-DC1394_FRAMERATE_MIN].name)
      current_rate=(dc1394framerate_t)m;
      return(_NO_ERROR_);
   } else
      return(_NO_VIDEORATE_);
}

//
// Get the current mode
//
dc1394mode dc1394camera::getMode() {
   return(dc1394modes[current_mode-DC1394_VIDEO_MODE_MIN]);
}

//
// Get the current frame rate
//
dc1394rate dc1394camera::getRate() {
   return(dc1394rates[current_rate-DC1394_FRAMERATE_MIN]);
}

//
// Get the current stream state (true : streaming, false : not streaming)
//
bool dc1394camera::getStreamState() {
   return(streamOn);
}

//
// Start capture
//
dc1394error dc1394camera::startCapture() {
   dc1394error_t err;
   if(!streamOn) {
      dc1394_capture_setup(camera_handler, 4, DC1394_CAPTURE_FLAGS_DEFAULT);
      err=dc1394_video_set_transmission(camera_handler, DC1394_ON);
      if(err==DC1394_SUCCESS) {
         streamOn=true;
         return(_NO_ERROR_);
      } else
         return(_NO_STREAM_);
   }
   return(_NO_ERROR_);
}

//
// Stop capture
//
dc1394error dc1394camera::stopCapture() {
   dc1394error_t err;
   if(streamOn) {
      err=dc1394_capture_stop(camera_handler);
      if(err==DC1394_SUCCESS) {
         streamOn=false;
         return(_NO_ERROR_);
      } else
         return(_NO_STREAM_);
   }
   return(_NO_ERROR_);
}

//
// Grab a frame
//
frame* dc1394camera::grabFrame() {
   frame* newFrame=NULL;
   dc1394video_frame_t* dcFrame;
   dc1394error_t err;

   err=dc1394_capture_dequeue(camera_handler, DC1394_CAPTURE_POLICY_WAIT, &dcFrame);
   if(err==DC1394_SUCCESS) {
      err=dc1394_capture_enqueue(camera_handler, dcFrame);

      // TO DO

      return(newFrame);
   } else
      return(NULL);
}
